/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { RuleListUtil } from "../../utils/common/DefectsList";
import { ArkFile, ts } from "arkanalyzer/lib";
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from "../BaseChecker";
import { Defects, IssueReport } from "../../model/Defects";
import { FileMatcher, MatcherCallback, MatcherTypes } from "../../matcher/Matchers";
import { AstTreeUtils } from "arkanalyzer";
import { Rule } from "../../model/Rule";
import { RuleFix } from '../../model/Fix';
import { console } from "inspector";
const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'PreferStringStartsRndsWith');

interface LocationInfo {
    line: number;
    character: number;
    startCol: number;
    endCol: number;
    isStartWith: boolean,
    methodName: string,
    testObjectText?: string;
    textEExpectedStr?: string;
}

export class PreferStringStartsEndsWithCheck implements BaseChecker {
    public rule: Rule;
    public defects: Defects[] = [];
    public typeChecker: ts.TypeChecker;
    public issues: IssueReport[] = [];
    private fixKeys: string[] = [];
    public metaData: BaseMetaData = {
        severity: 2,
        ruleDocPath: 'docs/prefer-string-starts-ends-with.md',
        description: "Use 'String#startsWith' method instead.",
    };
    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    public registerMatchers(): MatcherCallback[] {
        const fileMatcher: MatcherCallback = {
            matcher: this.fileMatcher,
            callback: this.check
        }
        return [fileMatcher];
    }

    public check = (target: ArkFile) => {
        const filePath = target.getFilePath();
        let code = target.getCode()?.toString() ?? '';
        const sourceFile = AstTreeUtils.getASTNode(target.getName(), code);
        const program = ts.createProgram([filePath], {});
        this.typeChecker = program.getTypeChecker();
        this.PreferStringStartsEndsWithCheck(sourceFile, this.typeChecker).forEach((item) => {
            this.addIssueReportNodeFix(sourceFile, item, filePath)
        });
    }

    public PreferStringStartsEndsWithCheck(sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker): LocationInfo[] {
        const results: LocationInfo[] = [];
        const visitedNodes = new Set<ts.Node>(); // 用于存储已经检测过的节点

        const visit = (node: ts.Node): void => {
            if (visitedNodes.has(node)) {
                return; // 如果节点已经检测过，直接跳过
            }
            visitedNodes.add(node); // 将节点添加到已检测集合中
            // 检测 CallExpression
            if (ts.isCallExpression(node)) {
                const expression = node.expression;
                // 检测 startsWith 和 endsWith
                if (this.isStartsWithOrEndsWithCall(expression)) {
                    const object = this.getObjectExpression(expression);
                    if (this.isStringContext(object, sourceFile)) {
                        return;
                    }
                }
                // 检测 charAt、indexOf、slice、substring、match 等方法
                const methodName = this.getMethodName(expression);
                if (methodName === 'test' && ts.isPropertyAccessExpression(expression)) {
                    const args = node.arguments; // 获取test方法的参数
                    if (args.length === 0) return; // 无参数直接返回
                    const testCallObject = args[0].getText(); // 新增调用
                    // 修改原始代码中的test方法检测逻辑
                    if (methodName === 'test' && ts.isPropertyAccessExpression(expression)) {
                        const propertyAccess = expression as ts.PropertyAccessExpression;
                        if (ts.isRegularExpressionLiteral(propertyAccess.expression)) {
                            const regexLiteral = propertyAccess.expression;
                            const regexText = regexLiteral.getText().slice(1, -1); // 去掉正则的/符号
                            // 解析正则表达式特征
                            // 增加最小长度限制和字符限制
                            const isStartsWithPattern =
                                regexText.startsWith('^') &&
                                regexText.length > 1 && // 排除空正则
                                !/[A-Z]/.test(regexText) && // 排除包含大写字母
                                !/[\\]/.test(regexText); // 排除包含转义字符

                            const isEndsWithPattern = regexText.endsWith('$') &&
                                !regexText.includes('^') &&
                                !/[^\\][|()*+?{}]/.test(regexText);

                            // 专门处理 startsWith 的正则模式
                            if (isStartsWithPattern &&
                                !regexText.includes('$') &&  // 确保不包含结束符
                                !/[^\\][|()*+?{}]/.test(regexText)) {
                                const expectedStr = regexText
                                    .replace(/^\^/, '')
                                    .replace(/\\\//g, '/')
                                    .replace(/\\/g, '');
                                this.addResult(sourceFile, node, true, "test", testCallObject, expectedStr, results);
                            }

                            // 专门处理 endsWith 的正则模式 
                            else if (isEndsWithPattern &&
                                !regexText.includes('^') &&  // 确保不包含开始符
                                !/[^\\][|()*+?{}]/.test(regexText)) {
                                const expectedStr = regexText
                                    .replace(/\$$/, '')
                                    .replace(/\\\//g, '/')
                                    .replace(/\\/g, '');

                                this.addResult(sourceFile, node, false, "test", testCallObject, expectedStr, results);
                            }
                        } else if (ts.isIdentifier(propertyAccess.expression)) {
                            const regexVar = propertyAccess.expression;
                            // 获取当前作用域块
                            let currentBlock = regexVar.parent;
                            while (currentBlock && !ts.isBlock(currentBlock) && !ts.isSourceFile(currentBlock)) {
                                currentBlock = currentBlock.parent;
                            }
                            // 递归解析变量
                            const resolved = this.resolveVariableInitializer(regexVar.text, currentBlock);
                            if (resolved.value) {
                                const regexText = resolved.value
                                    .replace(/^\/|\/$/g, '')  // 移除正则头尾斜杠
                                    .replace(/\\\//g, '/');
                                const isStartsWithPattern =
                                    regexText.startsWith('^') &&
                                    regexText.length > 1 && // 排除空正则
                                    !/[A-Z]/.test(regexText) && // 排除包含大写字母
                                    !/[\\]/.test(regexText); // 排除包含转义字符

                                const isEndsWithPattern = regexText.endsWith('$') &&
                                    !regexText.includes('^') &&
                                    !/[^\\][|()*+?{}]/.test(regexText);
                                // 专门处理 startsWith 的正则模式
                                if (isStartsWithPattern &&
                                    !regexText.includes('$') &&  // 确保不包含结束符
                                    !/[^\\][|()*+?{}]/.test(regexText)) {
                                    const expectedStr = regexText
                                        .replace(/^\^/, '')
                                        .replace(/\\\//g, '/')
                                        .replace(/\\/g, '');
                                    this.addResult(sourceFile, node, true, "test", testCallObject, expectedStr, results);
                                }
                                // 专门处理 endsWith 的正则模式 
                                else if (isEndsWithPattern &&
                                    !regexText.includes('^') &&  // 确保不包含开始符
                                    !/[^\\][|()*+?{}]/.test(regexText)) {
                                    const expectedStr = regexText
                                        .replace(/\$$/, '')
                                        .replace(/\\\//g, '/')
                                        .replace(/\\/g, '');
                                    this.addResult(sourceFile, node, false, "test", testCallObject, expectedStr, results);
                                }
                            }
                        }
                    }
                }
            }

            // 检测 BinaryExpression
            if (ts.isBinaryExpression(node)) {
                const left = node.left;
                const right = node.right;
                // 检测 foo[0] === 'b' 或 foo[foo.length - 1] === 'b'
                if (ts.isElementAccessExpression(left)) {
                    const elementAccess = left as ts.ElementAccessExpression;
                    const object = this.getObjectExpression(elementAccess);
                    // 新增索引值检查
                    const indexArgument = elementAccess.argumentExpression;
                    if (ts.isNumericLiteral(indexArgument) && indexArgument.text === '0') {
                        if (this.isStringContext(object, sourceFile)) {
                            this.addResult(sourceFile, node, true, "noName", object?.getText(), right.getText(), results);
                        }
                    } // 新增检测length-1的情况
                    else if (ts.isBinaryExpression(indexArgument)) {
                        const binExpr = indexArgument;
                        if (binExpr.operatorToken.kind === ts.SyntaxKind.MinusToken &&
                            ts.isPropertyAccessExpression(binExpr.left) &&
                            binExpr.left.name.text === 'length' &&
                            ts.isIdentifier(binExpr.left.expression) &&
                            binExpr.left.expression.text === object?.getText() &&
                            ts.isNumericLiteral(binExpr.right) &&
                            binExpr.right.text === '1') {
                            if (this.isStringContext(object, sourceFile)) {
                                this.addResult(sourceFile, node, false, "noName", object?.getText(), right.getText(), results);
                            }
                        }
                    }
                }

                // 处理charAt
                if (ts.isCallExpression(left)) {
                    const callExpression = left as ts.CallExpression;
                    if (callExpression.arguments.length < 1) return; // 新增参数校验
                    const objExpression = this.getObjectExpression(callExpression.expression);
                    const methodName = this.getMethodName(callExpression.expression);
                    if (methodName === 'charAt' && this.isStringContext(objExpression, sourceFile)) {
                        const isComparison = [
                            ts.SyntaxKind.EqualsEqualsToken,
                            ts.SyntaxKind.EqualsEqualsEqualsToken,
                            ts.SyntaxKind.ExclamationEqualsToken,
                            ts.SyntaxKind.ExclamationEqualsEqualsToken
                        ].includes(node.operatorToken.kind);
                        const indexArgument = callExpression.arguments[0];
                        // 专门处理 startsWith 情况（索引0检测）
                        if (isComparison && indexArgument &&
                            ts.isNumericLiteral(indexArgument) &&
                            indexArgument.text === '0') {
                            this.addResult(sourceFile, node, true, "charAt", objExpression?.getText(), right.getText(), results);
                        }
                        // 专门处理 endsWith 情况（末尾字符检测）
                        else if (isComparison && indexArgument &&
                            this.isLastCharacterCheck(callExpression.expression, indexArgument, typeChecker)) {
                            this.addResult(sourceFile, node, false, "charAt", objExpression?.getText(), right.getText(), results);
                        }
                    }
                    // 独立处理 indexOf 方法
                    if (methodName === 'indexOf' && ts.isCallExpression(left)) {
                        const callExpr = left as ts.CallExpression;
                        if (callExpr.arguments.length < 1) return;
                        const objExpression = this.getObjectExpression(callExpr.expression);
                        if (!objExpression || !this.isStringContext(objExpression, sourceFile)) return;
                        let artString = callExpr.arguments[0].getText()
                        const parent = callExpr.parent;
                        if (parent && ts.isBinaryExpression(parent)) {
                            const operatorToken = parent.operatorToken.kind;
                            const validOperators = [
                                ts.SyntaxKind.EqualsEqualsToken,
                                ts.SyntaxKind.EqualsEqualsEqualsToken,
                                ts.SyntaxKind.ExclamationEqualsToken,
                                ts.SyntaxKind.ExclamationEqualsEqualsToken
                            ];
                            // 保留原有 indexOf 的 0 值检测
                            const isZero = ts.isNumericLiteral(parent.right) && parent.right.text === '0';

                            if (validOperators.includes(operatorToken) && isZero) {
                                this.addResult(sourceFile, node, true, "indexOf", objExpression?.getText(), artString, results);
                            }
                        }
                    }

                    // 独立处理 lastIndexOf 方法
                    if (methodName === 'lastIndexOf' && ts.isCallExpression(left)) {
                        const callExpr = left as ts.CallExpression;
                        if (callExpr.arguments.length < 1) return;
                        const objExpression = this.getObjectExpression(callExpr.expression);
                        if (!objExpression || !this.isStringContext(objExpression, sourceFile)) return;
                        let artString = callExpr.arguments[0].getText()
                        const parent = callExpr.parent;
                        if (parent && ts.isBinaryExpression(parent)) {
                            const operatorToken = parent.operatorToken.kind;
                            const validOperators = [
                                ts.SyntaxKind.EqualsEqualsToken,
                                ts.SyntaxKind.EqualsEqualsEqualsToken,
                                ts.SyntaxKind.ExclamationEqualsToken,
                                ts.SyntaxKind.ExclamationEqualsEqualsToken
                            ];

                            // 获取搜索字符串参数
                            const searchStr = callExpr.arguments[0];
                            if (!searchStr) return;

                            // 需要补充的解析逻辑开始
                            let targetLength: number | undefined;
                            let textEExpectedStr: string;

                            // 处理两种参数类型：字面量和变量
                            if (ts.isStringLiteral(searchStr)) {
                                // 直接获取字面量值
                                targetLength = searchStr.text.length;
                                textEExpectedStr = `"${searchStr.text}"`;
                            } else if (ts.isIdentifier(searchStr)) {
                                // 获取当前作用域块
                                let currentBlock = searchStr.parent;
                                while (currentBlock && !ts.isBlock(currentBlock) && !ts.isSourceFile(currentBlock)) {
                                    currentBlock = currentBlock.parent;
                                }
                                // 使用递归解析方法
                                const resolved = this.resolveVariableInitializer(searchStr.text, currentBlock);

                                if (resolved.value !== undefined) {
                                    targetLength = resolved.value.length;
                                    textEExpectedStr = searchStr.text; // 保留原始变量名
                                } else {
                                    return;
                                }
                            } else {
                                return; // 非字符串字面量/变量时退出
                            }
                            // 需要补充的解析逻辑结束
                            const isLengthComparison = ts.isBinaryExpression(parent.right) &&
                                parent.right.operatorToken.kind === ts.SyntaxKind.MinusToken &&
                                ts.isPropertyAccessExpression(parent.right.left) &&
                                parent.right.left.name.text === 'length' &&
                                ts.isNumericLiteral(parent.right.right) &&
                                parseInt(parent.right.right.text) === targetLength;
                            if (validOperators.includes(operatorToken) && isLengthComparison) {
                                this.addResult(sourceFile, node, false, "lastIndexOf", objExpression?.getText(), artString, results);
                            }
                        }
                    }

                    if (methodName === 'slice' && ts.isCallExpression(left)) {
                        const callExpr = left as ts.CallExpression;
                        if (callExpr.arguments.length < 1) return; // 新增参数校验
                        const objExpression = this.getObjectExpression(callExpr.expression);

                        // 验证对象表达式和字符串上下文
                        if (!objExpression || !this.isStringContext(objExpression, sourceFile)) return;
                        const args = callExpr.arguments;
                        const parent = callExpr.parent;

                        // 只处理二元表达式中的相等比较
                        if (ts.isBinaryExpression(parent)) {
                            const operatorToken = parent.operatorToken.kind;
                            const validOperators = [
                                ts.SyntaxKind.EqualsEqualsToken,
                                ts.SyntaxKind.EqualsEqualsEqualsToken
                            ];

                            if (!validOperators.includes(operatorToken)) return;

                            // 处理右侧表达式
                            const rightExpression = parent.right;
                            let targetExpression: string | undefined;
                            let targetValue: string | undefined;

                            // 字符串字面量处理
                            if (ts.isStringLiteral(rightExpression)) {
                                targetExpression = `"${rightExpression.text}"`;
                                targetValue = rightExpression.text;
                            }
                            // 模板字符串处理
                            else if (ts.isNoSubstitutionTemplateLiteral(rightExpression)) {
                                targetExpression = `\`${rightExpression.text}\``;
                                targetValue = rightExpression.text;
                            }
                            // 变量引用处理
                            else if (ts.isIdentifier(rightExpression)) {
                                // 获取当前作用域块
                                let currentBlock = rightExpression.parent;
                                while (currentBlock && !ts.isBlock(currentBlock) && !ts.isSourceFile(currentBlock)) {
                                    currentBlock = currentBlock.parent;
                                }

                                // 使用递归解析方法
                                const resolved = this.resolveVariableInitializer(rightExpression.text, currentBlock);

                                if (resolved.value !== undefined) {
                                    targetExpression = rightExpression.text;
                                    targetValue = resolved.value;
                                } else {
                                    return;
                                }
                            }

                            // 跳过无效目标值
                            if (!targetValue || !targetExpression) return;

                            // 处理slice(0, n)的情况
                            if (args.length >= 2 &&
                                ts.isNumericLiteral(args[0]) &&
                                args[0].text === '0' &&
                                ts.isNumericLiteral(args[1])) {
                                const sliceLength = parseInt(args[1].text);
                                if (sliceLength === targetValue.length) {
                                    // 记录检测结果
                                    this.addResult(sourceFile, node, true, "slice", objExpression?.getText(), targetExpression, results);
                                }
                            }

                            // 处理slice(-n)的情况
                            if (args.length === 1 &&
                                ts.isPrefixUnaryExpression(args[0]) &&
                                args[0].operator === ts.SyntaxKind.MinusToken &&
                                ts.isNumericLiteral(args[0].operand)) {
                                const sliceLength = parseInt(args[0].operand.text);
                                if (sliceLength === targetValue.length) {
                                    // 记录检测结果
                                    this.addResult(sourceFile, node, false, "slice", objExpression?.getText(), targetExpression, results);
                                }
                            }
                        }
                    }

                    // 在BinaryExpression处理块中找到slice检测部分，添加以下代码：
                    if (methodName === 'substring' && ts.isCallExpression(left)) {
                        const callExpr = left as ts.CallExpression;
                        if (callExpr.arguments.length < 1) return; // 新增参数校验
                        const objExpression = this.getObjectExpression(callExpr.expression);
                        if (!objExpression || !this.isStringContext(objExpression, sourceFile)) return;
                        const args = callExpr.arguments;
                        const parent = callExpr.parent;
                        if (ts.isBinaryExpression(parent)) {
                            const operatorToken = parent.operatorToken.kind;
                            const validOperators = [
                                ts.SyntaxKind.EqualsEqualsToken,
                                ts.SyntaxKind.EqualsEqualsEqualsToken
                            ];

                            // 只处理相等比较
                            if (!validOperators.includes(operatorToken)) return;

                            // 修改右侧处理开始
                            const rightExpression = parent.right;
                            let targetExpression: string | undefined;
                            let targetValue: string | undefined;
                            // 处理字符串字面量
                            if (ts.isStringLiteral(rightExpression)) {
                                targetExpression = `"${rightExpression.text}"`;
                                targetValue = rightExpression.text;
                            }
                            // 处理字符串字面量
                            if (ts.isStringLiteral(rightExpression)) {
                                targetExpression = `"${rightExpression.text}"`;
                                targetValue = rightExpression.text;
                            }
                            // 处理变量引用（新增逻辑）
                            else if (ts.isIdentifier(rightExpression)) {
                                // 获取当前作用域块
                                let currentBlock = rightExpression.parent;
                                while (currentBlock && !ts.isBlock(currentBlock) && !ts.isSourceFile(currentBlock)) {
                                    currentBlock = currentBlock.parent;
                                }

                                // 使用递归解析方法
                                const resolved = this.resolveVariableInitializer(rightExpression.text, currentBlock);

                                if (resolved.value !== undefined) {
                                    targetExpression = rightExpression.text;
                                    targetValue = resolved.value;
                                } else {
                                    return;
                                }
                            }

                            if (!targetValue || !targetExpression) return;
                            // 修改检测结果推送部分
                            if (args.length >= 2 &&
                                ts.isNumericLiteral(args[0]) &&
                                args[0].text === '0' &&
                                ts.isNumericLiteral(args[1])) {
                                const sliceLength = parseInt(args[1].text);
                                // 使用targetValue替代原parent.right.text
                                if (sliceLength === targetValue.length) {
                                    this.addResult(sourceFile, node, true, "substring", objExpression?.getText(), targetExpression, results);
                                }
                            }
                            // 修改length - n检测部分
                            if (args.length === 1 &&
                                ts.isBinaryExpression(args[0]) &&
                                args[0].operatorToken.kind === ts.SyntaxKind.MinusToken) {
                                const binExpr = args[0];
                                if (ts.isPropertyAccessExpression(binExpr.left) &&
                                    binExpr.left.name.text === 'length' &&
                                    ts.isIdentifier(binExpr.left.expression) &&
                                    binExpr.left.expression.text === objExpression.getText() &&
                                    ts.isNumericLiteral(binExpr.right)) {
                                    const sliceLength = parseInt(binExpr.right.text);
                                    // 使用targetValue替代原parent.right.text
                                    if (sliceLength === targetValue.length) {
                                        this.addResult(sourceFile, node, false, "substring", objExpression?.getText(), targetExpression, results);
                                    }
                                }
                            }
                        }
                    }

                    // 处理match方法
                    if (methodName === 'match' && ts.isCallExpression(left)) {
                        const callExpr = left as ts.CallExpression;
                        const methodExpr = callExpr.expression;
                        if (!ts.isPropertyAccessExpression(methodExpr)) return;
                        // 新增参数检查
                        if (callExpr.arguments.length === 0) return; // 无参数时跳过检测
                        const objExpression = this.getObjectExpression(methodExpr);
                        if (!objExpression || !this.isStringContext(objExpression, sourceFile)) return;
                        const [regexArg] = callExpr.arguments;
                        let regexText: string | undefined;
                        // 处理字面量和变量两种情形
                        // 增强变量声明追溯逻辑
                        // 在match检测部分修改：
                        if (ts.isIdentifier(regexArg)) {
                            // 获取当前作用域块
                            let currentBlock = regexArg.parent;
                            while (currentBlock && !ts.isBlock(currentBlock) && !ts.isSourceFile(currentBlock)) {
                                currentBlock = currentBlock.parent;
                            }
                            // 使用递归解析方法
                            const resolved = this.resolveVariableInitializer(regexArg.text, currentBlock);
                            if (resolved.value) {
                                regexText = resolved.value
                            }
                        }// 原有字面量处理保持不变
                        else if (ts.isRegularExpressionLiteral(regexArg)) {
                            regexText = regexArg.getText();
                        }

                        if (!regexText) return;
                        const pattern = regexText.slice(1, -1).replace(/\\\//g, '/');
                        // 更严格的startsWith模式检测
                        const isStartsWithPattern = pattern.startsWith('^') &&
                            !pattern.includes('$') &&
                            !/[^\\][|()]/.test(pattern) &&
                            !pattern.includes('.') && // 不允许包含点号
                            !pattern.includes('*') && // 不允许包含星号
                            !pattern.includes('+') && // 不允许包含加号
                            !pattern.includes('?') && // 不允许包含问号
                            !pattern.includes('\\'); // 不允许包含转义字符
                        // 更严格的endsWith模式检测
                        const isEndsWithPattern = pattern.endsWith('$') &&
                            !pattern.includes('^') &&
                            pattern.indexOf('$') === pattern.length - 1 &&
                            !/[^\\][|()]/.test(pattern) &&
                            !pattern.includes('.') && // 不允许包含点号
                            !pattern.includes('*') && // 不允许包含星号
                            !pattern.includes('+') && // 不允许包含加号
                            !pattern.includes('?') && // 不允许包含问号
                            !pattern.includes('\\'); // 不允许包含转义字符
                        const parent = callExpr.parent;
                        if (ts.isBinaryExpression(parent)) {
                            const operatorToken = parent.operatorToken.kind;
                            const isNullComparison = [
                                ts.SyntaxKind.ExclamationEqualsToken,
                                ts.SyntaxKind.ExclamationEqualsEqualsToken
                            ].includes(operatorToken) &&
                                parent.right.kind === ts.SyntaxKind.NullKeyword;
                            if (isNullComparison) {
                                if (isStartsWithPattern) {
                                    const expectedStr = pattern.substring(1).replace(/\\/g, '');
                                    this.addResult(sourceFile, node, true, "match", objExpression?.getText(), expectedStr, results);
                                }

                                if (isEndsWithPattern) {
                                    const expectedStr = pattern.slice(0, -1).replace(/\\/g, '');
                                    this.addResult(sourceFile, node, false, "match", objExpression?.getText(), expectedStr, results);
                                }
                            }
                        }
                    }
                }
            }
            // 递归遍历子节点
            ts.forEachChild(node, visit);
        };

        // 开始遍历
        ts.forEachChild(sourceFile, visit);
        return results; // 返回检测结果
    }

    private isStartsWithOrEndsWithCall(expression: ts.LeftHandSideExpression): boolean {
        const methodName = this.getMethodName(expression);
        return methodName === 'startsWith' || methodName === 'endsWith';
    }

    private getMethodName(expression: ts.LeftHandSideExpression): string | undefined {
        if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
            const propertyAccess = expression as ts.PropertyAccessExpression;
            return propertyAccess.name.getText();
        } else if (expression.kind === ts.SyntaxKind.ElementAccessExpression) {
            const elementAccess = expression as ts.ElementAccessExpression;
            const argument = elementAccess.argumentExpression;
            if (argument.kind === ts.SyntaxKind.NumericLiteral) {
                return (argument as ts.NumericLiteral).text;
            }
        }
        return undefined;
    }
    // 递归解析变量初始值
    private resolveVariableInitializer(varName: string, block: ts.Node, depth: number = 0): {
        value?: string;
    } {
        if (depth > 10) return {}; // 防止无限递归

        const declaration = this.findVariableDeclarationInBlock(varName, block);
        if (!declaration?.initializer) return {};
        const initializer = declaration.initializer;
        // 处理字符串字面量
        if (ts.isStringLiteral(initializer)) {
            return { value: initializer.text };
        }
        // 处理模板字符串
        else if (ts.isNoSubstitutionTemplateLiteral(initializer)) {
            return { value: initializer.text };
        }  // 新增正则表达式字面量处理
        else if (ts.isRegularExpressionLiteral(initializer)) {
            return { value: initializer.getText() };
        }
        // 递归处理变量引用
        else if (ts.isIdentifier(initializer)) {
            return this.resolveVariableInitializer(initializer.text, block, depth + 1);
        }
        return {};
    }
    private getObjectExpression(expression: ts.Expression): ts.Expression | undefined {
        if (ts.isPropertyAccessExpression(expression)) {
            const propertyAccess = expression as ts.PropertyAccessExpression;
            return propertyAccess.expression;
        } else if (ts.isElementAccessExpression(expression)) {
            const elementAccess = expression as ts.ElementAccessExpression;
            return elementAccess.expression;
        } else if (ts.isCallExpression(expression)) {
            return this.getObjectExpression(expression.expression);
        }
        return undefined;
    }

    private isStringContext(node: ts.Expression | undefined, sourceFile: ts.SourceFile): boolean {
        if (!node) return false;
        // 新增作用域安全检测
        if (ts.isIdentifier(node)) {
            // 类方法内部变量检测
            if (this.isClassMethodVariable(node)) {
                const symbol = this.findVariableDeclaration(node.text, node);
                return symbol ? this.inferStringType(symbol) : false;
            }
            // 全局声明检测
            else {
                try {
                    const type = this.typeChecker.getTypeAtLocation(node);
                    return (type.flags & ts.TypeFlags.String) !== 0;
                } catch (e) {
                    return this.checkGlobalDeclaration(node);
                }
            }
        }
        return false;
    }
    // 新增类方法变量检测方法
    private isClassMethodVariable(node: ts.Identifier): boolean {
        let parent = node.parent;
        while (parent) {
            if (ts.isMethodDeclaration(parent) || ts.isClassDeclaration(parent) || ts.isFunctionDeclaration(parent)) {
                return true;
            }
            parent = parent.parent;
        }
        return false;
    }

    // 新增全局声明检测方法
    private checkGlobalDeclaration(node: ts.Identifier): boolean {
        const symbol = this.typeChecker.getSymbolAtLocation(node);
        return symbol?.declarations?.some(decl =>
            ts.isVariableDeclaration(decl) &&
            decl.type?.getText() === 'string'
        ) ?? false;
    }

    // 带作用域限制的变量查找
    private findVariableDeclaration(varName: string, currentNode: ts.Node): ts.Node | undefined {
        let scopeNode: ts.Node | undefined = currentNode;
        while (scopeNode) {
            // 在当前作用域内查找变量声明
            const declaration = this.findInCurrentScope(varName, scopeNode);
            if (declaration) return declaration;
            // 向上层作用域查找（限制在函数/类作用域内）
            scopeNode = this.getParentScope(scopeNode);
        }
        return undefined;
    }
    // 作用域边界判断
    // 修改作用域边界判断逻辑
    private getParentScope(node: ts.Node): ts.Node | undefined {
        let parent = node.parent;
        while (parent) {
            if (ts.isFunctionLike(parent) ||
                ts.isClassDeclaration(parent) ||
                ts.isBlock(parent) ||       // 增加块级作用域判断
                ts.isMethodDeclaration(parent)) { // 处理类方法
                return parent;
            }
            parent = parent.parent;
        }
        return undefined;
    }
    private findInCurrentScope(varName: string, scopeNode: ts.Node): ts.Node | undefined {
        let declaration: ts.Node | undefined;
        const deepSearch = (node: ts.Node) => {
            // 新增：处理函数/方法的参数列表
            if (ts.isFunctionLike(node)) {
                node.parameters.forEach(param => {
                    if (param.name.getText() === varName) {
                        declaration = param;
                    }
                });
            }
            // 原有变量声明处理逻辑
            if (ts.isVariableStatement(node)) {
                node.declarationList.declarations.forEach(decl => {
                    if (ts.isIdentifier(decl.name) && decl.name.text === varName) {
                        declaration = decl;
                    }
                });
            }
        };

        // 特殊处理函数/类方法的情况
        if (ts.isFunctionLike(scopeNode)) {
            // 遍历参数列表
            scopeNode.parameters.forEach(param => {
                if (param.name.getText() === varName) {
                    declaration = param;
                }
            });
            if (ts.isMethodDeclaration(scopeNode)) {
                if (scopeNode.body) {
                    ts.forEachChild(scopeNode.body, deepSearch);
                }
            }
            // 遍历函数体内容
        } else {
            ts.forEachChild(scopeNode, deepSearch);
        }

        return declaration;
    }

    // AST遍历查找变量声明
    private findVariableDeclarationInBlock(varName: string, block: ts.Node): ts.VariableDeclaration | undefined {
        let result: ts.VariableDeclaration | undefined;
        const visit = (node: ts.Node) => {
            if (ts.isVariableStatement(node)) {
                node.declarationList.declarations.forEach(decl => {
                    if (ts.isIdentifier(decl.name) && decl.name.text === varName) {
                        result = decl;
                    }
                });
            }
            ts.forEachChild(node, visit);
        };
        ts.forEachChild(block, visit);
        return result;
    }    // 类型推断逻辑
    private inferStringType(declaration: ts.Node): boolean {
        // 增强参数类型检测
        if (ts.isParameter(declaration)) {
            const typeNode = declaration.type;
            if (typeNode) {
                // 处理简单类型标识符
                if (ts.isIdentifier(typeNode) && typeNode.text === 'string') {
                    return true;
                }
                // 处理类型引用（如String）
                if (ts.isTypeReferenceNode(typeNode) && typeNode.typeName.getText() === 'String') {
                    return true;
                }
            }
            // 处理带默认值的参数（需类型推断）
            if (declaration.initializer) {
                return this.checkInitializerType(declaration.initializer);
            }
        }
        // 处理变量声明
        if (ts.isVariableDeclaration(declaration)) {
            const initializer = declaration.initializer;
            if (initializer && ts.isStringLiteral(initializer)) {
                return true;
            }
        }

        // 处理函数参数（需结合函数调用分析）
        if (ts.isParameter(declaration)) {
            const paramType = declaration.type?.getText();
            return paramType === 'string' || paramType === 'String';
        }
        return false;
    }

    // 新增类型推断辅助方法
    private checkInitializerType(node: ts.Expression): boolean {
        if (ts.isStringLiteral(node)) return true;
        if (ts.isNewExpression(node) && node.expression.getText() === 'String') return true;
        return false;
    }
    private isLastCharacterCheck(expression: ts.Expression, indexArg: ts.Expression, checker: ts.TypeChecker): boolean {
        if (!ts.isPropertyAccessExpression(expression)) return false;
        // 匹配 pattern: .length - 1
        if (ts.isBinaryExpression(indexArg) &&
            ts.isPropertyAccessExpression(indexArg.left) &&
            ts.isIdentifier(indexArg.left.expression) &&
            indexArg.left.name.text === 'length' &&
            indexArg.operatorToken.kind === ts.SyntaxKind.MinusToken &&
            ts.isNumericLiteral(indexArg.right) &&
            indexArg.right.text === '1') {
            return true
        }
        return false;
    }

    private ruleFix(sourceFile: ts.SourceFile, loc: LocationInfo): RuleFix {
        const startPosition = sourceFile.getPositionOfLineAndCharacter(loc.line - 1, loc.startCol - 1);
        const endPosition = sourceFile.getPositionOfLineAndCharacter(loc.line - 1, loc.endCol - 1);
        if (loc.methodName === 'test' && loc.isStartWith) {
            const fixText = `${loc.testObjectText}.startsWith("${loc.textEExpectedStr}")`;
            return { range: [startPosition, endPosition], text: fixText };
        } else if (loc.methodName === 'test' && !loc.isStartWith) {
            const fixText = `${loc.testObjectText}.endsWith("${loc.textEExpectedStr}")`;
            return { range: [startPosition, endPosition], text: fixText };
        }

        if (loc.methodName === 'noName' && loc.isStartWith) {
            const fixText = `${loc.testObjectText}.startsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText };
        } else if (loc.methodName === 'noName' && !loc.isStartWith) {
            const fixText = `${loc.testObjectText}.endsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        }

        if (loc.methodName === 'charAt' && loc.isStartWith) {
            const fixText = `${loc.testObjectText}.startsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        } else if (loc.methodName === 'charAt' && !loc.isStartWith) {
            const fixText = `${loc.testObjectText}.endsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        }

        if (loc.methodName === 'match' && loc.isStartWith) {
            const fixText = `${loc.testObjectText}.startsWith("${loc.textEExpectedStr}")`;
            return { range: [startPosition, endPosition], text: fixText }
        } else if (loc.methodName === 'match' && !loc.isStartWith) {
            const fixText = `${loc.testObjectText}.endsWith("${loc.textEExpectedStr}")`;
            return { range: [startPosition, endPosition], text: fixText }
        }

        if (loc.methodName === 'slice' && loc.isStartWith) {
            const fixText = `${loc.testObjectText}.startsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        } else if (loc.methodName === 'slice' && !loc.isStartWith) {
            const fixText = `${loc.testObjectText}.endsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        }

        if (loc.methodName === 'substring' && loc.isStartWith) {
            const fixText = `${loc.testObjectText}.startsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        } else if (loc.methodName === 'substring' && !loc.isStartWith) {
            const fixText = `${loc.testObjectText}.endsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        }

        if (loc.methodName === 'indexOf') {
            const fixText = `${loc.testObjectText}.endsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        } else if (loc.methodName === 'lastIndexOf') {

            const fixText = `${loc.testObjectText}.endsWith(${loc.textEExpectedStr})`;
            return { range: [startPosition, endPosition], text: fixText }
        }
        // 新增默认返回值
        return { range: [0, 0], text: "" }; // 或根据业务需求返回合法空值
    }

    private addIssueReportNodeFix(sourceFile: ts.SourceFile, loc: LocationInfo, filePath: string) {
        const severity = this.rule.alert ?? this.metaData.severity;
        const currentFixKey = loc.line + '%' + loc.startCol + '%' + loc.endCol + '%' + this.rule.ruleId;
        const fixKey = this.fixKeys.find(key => key === currentFixKey) || currentFixKey;
        const mergeKey = filePath + '%' + fixKey + '%' + this.metaData.description;
        const defect = new Defects(loc.line, loc.character, "Use 'String#startsWith' method instead.", severity, this.rule.ruleId,
            mergeKey, this.metaData.ruleDocPath, true, false, false, fixKey);
        let fix: RuleFix = this.ruleFix(sourceFile, loc);
        this.issues.push(new IssueReport(defect, fix));
        RuleListUtil.push(defect);
    }

    private getLineAndCharacterInfo(sourceFile: ts.SourceFile, node: ts.Node): { line: number; character: number; startCol: number; endCol: number } {
        const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
        const lineStartOffset = sourceFile.getLineStarts()[line];
        return {
            line: line + 1,
            character: character + 1,
            startCol: node.getStart() - lineStartOffset + 1,
            endCol: node.getEnd() - lineStartOffset + 1
        };
    }

    private createLocationInfo(sourceFile: ts.SourceFile, node: ts.Node, isStartWith: boolean, methodName: string, testObjectText?: string, textEExpectedStr?: string): LocationInfo {
        const { line, character, startCol, endCol } = this.getLineAndCharacterInfo(sourceFile, node);
        return {
            line,
            character,
            startCol,
            endCol,
            isStartWith,
            methodName,
            testObjectText,
            textEExpectedStr
        };
    }

    private addResult(sourceFile: ts.SourceFile, node: ts.Expression, isStartWith: boolean, methodName: string, testObjectText?: string, textEExpectedStr?: string, results: LocationInfo[] = []): void {
        const locationInfo = this.createLocationInfo(sourceFile, node, isStartWith, methodName, testObjectText, textEExpectedStr);
        results.push(locationInfo);
    }
}